<template>
  <div class="home">
    <!--这个地方自定义背景-->
    <canvas id="backCanvas" />
    <div class="content">
      <div class="home-header">
        <router-link class="link" to="/home">
          <img src="@/assets/userLogo.jpg" alt="我的头像" class="home-logo" />
        </router-link>
      </div>
      <div class="home-body">
        <div class="list">
          <router-link class="link" to="/articles">文章</router-link>
          <router-link class="link" to="/project">项目</router-link>
          <a target="_blank" href="https://gitee.com/assd12138" class="link">gitee</a>
          <a target="_blank" href="https://github.com/assd12138" class="link">github</a>
        </div>
        <div class="introduce">fight！！</div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { throttle } from "../utils/utils";
declare let document: Document;

@Component({})
export default class Home extends Vue {
  mounted() {
    if (document.location.protocol === "http:") {
      this.$message({
        message: "请切换使用https访问本网站",
        type: "warning"
      });
    }
    if (window.ActiveXObject || "ActiveXObject" in window) {
      setTimeout(() => {
        this.$message({
          message: "强烈建议使用chrome/firefox浏览器或者极速模式浏览本网页",
          type: "warning"
        });
      }, 3000);
    }
    const len = 5; //初始的球的个数
    const ballList: Ball[] = [];
    let posX = 0;
    const gravity = 0.1;
    const canvas: HTMLCanvasElement = document.querySelector(
      "#backCanvas"
    ) as HTMLCanvasElement;
    const space = canvas.width / len;
    let posY = space;
    const context = canvas.getContext("2d")!;
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    function distance(x1: number, y1: number, x2: number, y2: number) {
      const r: number = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
      return r;
    }
    class Vector2d {
      x: number;
      y: number;
      constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
      }
      getRotateRad(
        cx: number,
        cy: number,
        x: number,
        y: number,
        radian: number
      ) {
        const cos = Math.cos(radian);
        const sin = Math.sin(radian);
        const nx = cos * (x - cx) + sin * (y - cy);
        const ny = cos * (y - cy) - sin * (x - cx);
        return { x: nx, y: ny };
      }
      rotateRad(cx: number, cy: number, x: number, y: number, radian: number) {
        const cos = Math.cos(radian);
        const sin = Math.sin(radian);
        this.x = cos * (x - cx) + sin * (y - cy);
        this.y = cos * (y - cy) - sin * (x - cx);
      }
      add(x: number, y: number) {
        this.x += x;
        this.y += y;
      }
      sub(x: number, y: number) {
        this.x -= x;
        this.y -= y;
      }
      mul(x: number, y: number) {
        this.x *= x;
        this.y *= y;
      }
    }

    class Eye {
      ball: Ball;
      eyeX: number;
      eyeY: number;
      eyeWhiteScale: number;
      eyeBlackScale: number;
      isBlink: boolean;
      constructor(ball: Ball) {
        this.ball = ball;
        this.eyeX = Math.random() * 7 + 5;
        this.eyeY = Math.random() * 4 + 5;
        this.eyeWhiteScale = Math.random() * 8 + 5;
        this.eyeBlackScale = Math.random() * 3 + 2;
        this.isBlink = false;
        this.blink();
      }
      blink() {
        setTimeout(() => {
          this.isBlink = !this.isBlink;
          this.blink();
          setTimeout(() => {
            this.isBlink = false;
          }, 100);
        }, Math.random() * 2000 + 300);
      }
      draw(context: CanvasRenderingContext2D) {
        // context.scale(1, 0.2);
        context.beginPath(); //パス作成
        //描写cmd start
        if (!this.isBlink) {
          context.arc(
            this.ball.x + this.eyeX,
            this.ball.y - this.eyeY,
            this.eyeWhiteScale,
            0,
            Math.PI * 2,
            true
          );
          context.arc(
            this.ball.x - this.eyeX,
            this.ball.y - this.eyeY,
            this.eyeWhiteScale,
            0,
            Math.PI * 2,
            true
          );
          context.fillStyle = "#fff"; //線の色指定
          context.fill(); //線を描写
          context.closePath();
          context.beginPath(); //パス作成
          context.arc(
            this.ball.x + this.eyeX,
            this.ball.y - this.eyeY,
            this.eyeBlackScale,
            0,
            Math.PI * 2,
            true
          );
          context.arc(
            this.ball.x - this.eyeX,
            this.ball.y - this.eyeY,
            this.eyeBlackScale,
            0,
            Math.PI * 2,
            true
          );
          context.fillStyle = "#000"; //線の色指定
          context.fill(); //線を描写
        }
      }
    }
    class Ball {
      x: number;
      y: number;
      defX: number;
      defY: number;
      vec: Vector2d;
      forceVec: Vector2d;
      speed: number;
      scale: number;
      life: number;
      mass: number;
      color: string;
      eye: Eye;
      isHit = false;
      isHitObj: any;
      hitdistance = 0;
      beforeX = 0;
      beforeY = 0;
      constructor(
        x: number,
        y: number,
        vecX: number,
        vecY: number,
        speed: number,
        scale: number
      ) {
        this.x = x;
        this.y = y;
        this.defX = x;
        this.defY = y;
        this.vec = new Vector2d(vecX, vecY);
        this.forceVec = new Vector2d(0, 0);
        this.speed = speed;
        this.scale = scale;
        this.life = Math.random() * 500 + 500;
        this.mass = scale;
        this.color = `rgb(${Math.random() * 100 + 155}, ${Math.random() * 150 +
          40}, ${Math.random() * 150 + 40})`;
        this.eye = new Eye(this);
      }
      setHit(val: boolean, hitObj: Ball | null, distance = 0) {
        this.isHit = true;
        this.isHitObj = hitObj;
        this.hitdistance = distance;
      }
      draw(context: CanvasRenderingContext2D) {
        context.beginPath(); //パス作成
        // 描写cmd start
        context.arc(this.x, this.y, this.scale, 0, 2 * Math.PI, true);
        context.fillStyle = this.color; //線の色指定
        context.fill(); //線を描写

        // vector表示
        context.beginPath();
        context.moveTo(this.x, this.y);
        context.lineTo(this.x + this.vec.x * 5, this.y + this.vec.y * 5);
        context.strokeStyle = "black";
        context.lineWidth = 1;
        context.stroke();
        context.closePath();
        this.eye.draw(context);
      }
      update() {
        this.beforeX = this.x;
        this.beforeY = this.y;
        if (this.isHit && this.isHitObj) {
          const rad = Math.atan2(
            this.isHitObj.y - this.y,
            this.isHitObj.x - this.x
          );

          const cos = Math.cos(rad);
          const sin = Math.sin(rad);
          // 衝突の重なり部分解消
          this.x += (this.hitdistance / 2) * cos;
          this.y += (this.hitdistance / 2) * sin;
          this.isHitObj.x -= (this.hitdistance / 2) * cos;
          this.isHitObj.y -= (this.hitdistance / 2) * sin;

          // 反射角出し参考
          // https://thinkit.co.jp/article/8466

          // 円同士の接点
          const cx = cos * this.scale + this.x;
          const cy = sin * this.scale + this.y;

          // 180度回転後の座標
          const rx = Math.cos(rad + Math.PI) * this.scale + this.x;
          const ry = Math.sin(rad + Math.PI) * this.scale + this.y;

          // 次の移動地点 反射後の地点
          const gx = rx + this.vec.x;
          const gy = ry + this.vec.y;

          this.vec.x = (gx - cx) / this.scale;
          this.vec.y = (gy - cy) / this.scale;

          this.setHit(false, null);
        }
        this.x += this.speed * (this.vec.x + this.forceVec.x);
        this.y += this.speed * (this.vec.y + this.forceVec.y);
        // 上にめり込んだら
        if (this.y - this.scale <= 0) {
          this.y = this.scale;
          this.vec.y *= -1;
          this.forceVec.y *= -1;
        }
        // 下にめり込んだら
        if (this.y + this.scale > canvas.height) {
          //this.y -= this.vec.y * this.speed;
          this.y = canvas.height - this.scale;
          this.vec.y *= -1;
          this.forceVec.y *= -1;
        }
        // 左にめり込んだ時
        if (this.x - this.scale <= 0) {
          //this.x -= this.vec.x * this.speed;
          this.x = this.scale;
          this.vec.x *= -1;
          this.forceVec.x *= -1;
        }
        // 右にめり込んだら
        if (this.x + this.scale > canvas.width) {
          //this.x -= this.vec.x * this.speed;
          this.x = canvas.width - this.scale;
          this.vec.x *= -1;
          this.forceVec.x *= -1;
        }
        this.vec.y += gravity;
        this.forceVec.mul(0.9, 0.9);
      }
    }
    function addBall(posX: number, posY: number) {
      const radian = Math.random() * Math.PI * 2;
      const vx = Math.sin(radian);
      const vy = Math.cos(radian);
      ballList.push(new Ball(posX, posY, vx, vy, 1, 20 + Math.random() * 15));
    }
    for (let i = 0; i < len; i++) {
      posX += space;
      if (posX >= canvas.width) {
        posY += space;
        posX = space;
      }
      addBall(posX, posY);
    }

    document.addEventListener("click", e => {
      if (document.location.pathname !== "/") return;
      for (let i = 0; i < ballList.length; i++) {
        ballList[i].forceVec.add(Math.random() * 10 - 5, Math.random() * -12);
      }
      addBall(e.offsetX, e.offsetY);
    });
    window.addEventListener(
      "resize",
      throttle(() => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
      }, 500)
    );
    function render() {
      context?.clearRect(0, 0, canvas.width, canvas.height);
      for (let i = 0; i < ballList.length; i++) {
        const ball = ballList[i];
        // 衝突判定
        for (let i2 = 0; i2 < ballList.length; i2++) {
          const ball2 = ballList[i2];
          if (i != i2) {
            const dis =
              distance(ball.x, ball.y, ball2.x, ball2.y) -
              (ball.scale + ball2.scale);
            if (dis < 0) {
              // hit
              ball.setHit(true, ball2, dis);
            }
          }
        }
        ball.update();
        ball.draw(context);
      }
      requestAnimationFrame(render);
    }

    render();
  }
}
</script>

<style lang="less" scoped>
.home {
  position: fixed;
  left: 0;
  top: 0;
  .content {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    font-size: 20px;
    text-align: center;
    padding-top: 12%;
    .home-logo {
      width: 220px;
      border-radius: 50%;
      transition: transform 3s;
      &:hover {
        transform: rotate(360deg);
        transition: transform 3s;
      }
    }
    .home-body {
      padding-top: 20px;
      .list {
        .link {
          display: inline-block;
          padding: 20px;
          color: #409eff;
          min-width: 80px;
        }
        .link:hover {
          color: rgb(155, 35, 35);
        }
      }
    }
    .introduce {
      padding-top: 20px;
      color: #fff;
    }
  }
  #backCanvas {
    background-color: rgb(253, 246, 227);
    z-index: -1;
    position: absolute;
    display: block;
    margin: 0 auto;
  }
}
</style>
